/****************************************************************************

Force Engine v0.5

Creado: 28/03/08
Clase: Vertex Buffer.inl
Hecho by: German Battiston AKA Melkor

****************************************************************************/

//---------------------------------------------------------------------------
template <class PixelFormatClass>
VertexBuffer<PixelFormatClass>::VertexBuffer (IDirect3DDevice9 * pkDevice, unsigned int uiFVF, bool bDynamic)
:
m_uiBase(0),
m_uiFlush(150),
m_uiVbSize(450),
m_uiFVF(uiFVF),
m_pkVertexBuffer(NULL),
m_pkDevice(pkDevice)
{
	HRESULT hr = pkDevice->CreateVertexBuffer(
											m_uiVbSize * sizeof(PixelFormatClass),
											(bDynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0),
											m_uiFVF,
											D3DPOOL_DEFAULT,
											&m_pkVertexBuffer,
											NULL
	);

	assert(hr == D3D_OK);
}
//---------------------------------------------------------------------------
template <class PixelFormatClass>
void VertexBuffer<PixelFormatClass>::draw (const PixelFormatClass* akVertices, D3DPRIMITIVETYPE ePrimitiveType, unsigned int uiVertexCount)
{
	m_ePrimitiveType = ePrimitiveType;

	if(m_uiFlush < uiVertexCount)
	{
		m_uiVtxToLock = m_uiFlush;
	}
	else
	{
		m_uiVtxToLock = uiVertexCount;
	}

	if((m_uiBase + m_uiVtxToLock) > m_uiVbSize)
	{
		m_uiBase = 0;
	}

	void* pVertices = NULL;

	HRESULT hr = m_pkVertexBuffer->Lock(
										m_uiBase * sizeof(PixelFormatClass),
										m_uiVtxToLock * sizeof(PixelFormatClass),
										(void **) (&pVertices),
										m_uiBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD
										);

	unsigned int uiVtxProcNow = 0;

	while(m_uiVtxToLock > 0)
	{
		memcpy(pVertices, &akVertices[uiVtxProcNow], sizeof(PixelFormatClass)* m_uiVtxToLock);

		uiVtxProcNow += m_uiVtxToLock;
		hr = m_pkVertexBuffer->Unlock();
		flush();

		m_uiBase += m_uiVtxToLock;

		if( m_uiBase > (m_uiVbSize - 1) )
		{
			m_uiBase = 0;
		}

		if( m_uiFlush < (uiVertexCount - uiVtxProcNow) )
		{
			m_uiVtxToLock = m_uiFlush;
		}
		else
		{
			m_uiVtxToLock = uiVertexCount - uiVtxProcNow;
		}

		hr = m_pkVertexBuffer->Lock(
								   m_uiBase * sizeof(PixelFormatClass), 
								   m_uiVtxToLock * sizeof(PixelFormatClass), 
								   (void **)(&pVertices),
								   m_uiBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD
								   );
	}

	m_pkVertexBuffer->Unlock();
	
}
//---------------------------------------------------------------------------
template <class PixelFormatClass>
void VertexBuffer<PixelFormatClass>::flush ()
{
	int iPrimitiveCount = 0;

	if(m_ePrimitiveType == D3DPT_POINTLIST)
	{
		iPrimitiveCount = m_uiVtxToLock;
	}
	else if(m_ePrimitiveType == D3DPT_LINELIST)
	{
		iPrimitiveCount = m_uiVtxToLock / 2;
	}
	else if(m_ePrimitiveType == D3DPT_LINESTRIP)
	{
		iPrimitiveCount = m_uiVtxToLock - 1;
	}
	else if(m_ePrimitiveType == D3DPT_TRIANGLELIST)
	{
		iPrimitiveCount = m_uiVtxToLock / 3;
	}
	else if(m_ePrimitiveType == D3DPT_TRIANGLESTRIP)
	{
		iPrimitiveCount = m_uiVtxToLock - 2;
	}
	else if(m_ePrimitiveType == D3DPT_TRIANGLEFAN)
	{
		iPrimitiveCount = m_uiVtxToLock - 2;
	}

	HRESULT hr = m_pkDevice->DrawPrimitive(m_ePrimitiveType, m_uiBase, iPrimitiveCount);

	assert(hr == D3D_OK);
}
//---------------------------------------------------------------------------
template <class PixelFormatClass>
void VertexBuffer<PixelFormatClass>::bind ()
{
	HRESULT hr;
	
	hr = m_pkDevice->SetVertexShader(NULL);
	hr = m_pkDevice->SetFVF(m_uiFVF);
	hr = m_pkDevice->SetStreamSource( 0, m_pkVertexBuffer, NULL, sizeof(PixelFormatClass) );
}
//---------------------------------------------------------------------------
